package cn.iocoder.yudao.module.mqtt.service.subscribewater;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.mqtt.dal.dataobject.config.MqttConfig2DO;
import cn.iocoder.yudao.module.mqtt.dal.dataobject.configalarm.ConfigAlarmDO;
import cn.iocoder.yudao.module.mqtt.dal.dataobject.devicealermrecord.DeviceAlermRecordDO;
import cn.iocoder.yudao.module.mqtt.dal.dataobject.devicelatestflow.DeviceLatestFlowDO;
import cn.iocoder.yudao.module.mqtt.dal.dataobject.systemconfig.SystemConfigDO;
import cn.iocoder.yudao.module.mqtt.dal.mysql.config.MqttConfig2Mapper;
import cn.iocoder.yudao.module.mqtt.dal.mysql.devicealermrecord.DeviceAlermRecordMapper;
import cn.iocoder.yudao.module.mqtt.dal.mysql.devicelatest.DeviceLatestFlowMapper;
import cn.iocoder.yudao.module.mqtt.enums.mqtt.DataTypeEnum;
import cn.iocoder.yudao.module.mqtt.framework.util.TenantContextUtil;
import cn.iocoder.yudao.module.mqtt.service.configalarm.ConfigAlarmService;
import cn.iocoder.yudao.module.mqtt.service.systemconfig.SystemConfigService;
import cn.iocoder.yudao.module.mqtt.util.MqttDeviceUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;

import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;

import cn.iocoder.yudao.module.mqtt.controller.admin.subscribewater.vo.*;
import cn.iocoder.yudao.module.mqtt.dal.dataobject.subscribewater.SubscribeWaterDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.mqtt.dal.mysql.subscribewater.SubscribeWaterMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.mqtt.enums.ErrorCodeConstants.*;

/**
 * MQTT水监控 Service 实现类
 *
 * @author 管理员
 */
@Slf4j
@Service
@Validated
public class SubscribeWaterServiceImpl implements SubscribeWaterService {

    @Resource
    private SubscribeWaterMapper subscribeWaterMapper;

    @Autowired
    private MqttConfig2Mapper mqttConfig2Mapper;

    @Resource
    ConfigAlarmService configAlarmService;

    @Resource
    SystemConfigService systemConfigService;

    @Resource
    private DeviceLatestFlowMapper deviceLatestMapper;


    @Resource
    private DeviceAlermRecordMapper deviceAlermRecordMapper;

    @Override
    public Long createSubscribeWater(SubscribeWaterSaveReqVO createReqVO) {
        // 插入
        SubscribeWaterDO subscribeWater = BeanUtils.toBean(createReqVO, SubscribeWaterDO.class);
        subscribeWaterMapper.insert(subscribeWater);
        // 返回
        return subscribeWater.getId();
    }


    /**
     * 异步执行一些额外的逻辑
     */
    @Async
    @Override
    public CompletableFuture<Long> createSubscribeWater(Long configId, String topic, String payload, Integer qos, Boolean retained, String clientId, String messageId) {
        //查询系统 数据 格式化 就是
        SystemConfigDO configDO = systemConfigService.getValue("wypz_data_fmt_divide");
        System.out.println(configDO.getSysValue());
        // 插入
        SubscribeWaterDO createReqVO = new SubscribeWaterDO();
        createReqVO.setMqttConfigId(configId);
        createReqVO.setTopic(topic);
        createReqVO.setPayload(payload);
        createReqVO.setQos(qos);
        createReqVO.setRetained(retained);
        createReqVO.setDirection("IN");
        createReqVO.setClientId(clientId);
        System.out.println("payload:" + payload);
        Map<String, Object> map = JSON.parseObject(payload, Map.class);
        createReqVO.setPayloadWd(MqttDeviceUtil.divideValues(map, "WD", configDO.getSysValue(), 5 ));
        createReqVO.setPayloadZd(MqttDeviceUtil.divideValues(map, "ZD", configDO.getSysValue(), 5 ));
        createReqVO.setPayloadYl(MqttDeviceUtil.divideValues(map, "YL", configDO.getSysValue(), 5 ));
        createReqVO.setPayloadPh(MqttDeviceUtil.divideValues(map, "PH", configDO.getSysValue(), 5 ));
        subscribeWaterMapper.insert(createReqVO);

        if(ObjectUtil.isNotEmpty(map.get("ID"))){
            String devicekey = map.get("ID").toString();
            DeviceLatestFlowDO deviceLatestDO = new DeviceLatestFlowDO();
            deviceLatestDO.setDeviceKey(devicekey);
//            deviceLatestDO.setPayloadWd(createReqVO.getPayloadWd());
//            deviceLatestDO.setPayloadZd(createReqVO.getPayloadZd());
//            deviceLatestDO.setPayloadYl(createReqVO.getPayloadYl());
//            deviceLatestDO.setPayloadPh(createReqVO.getPayloadPh());
            deviceLatestMapper.update(deviceLatestDO,
                    new QueryWrapper<DeviceLatestFlowDO>().eq("device_key",devicekey));
        }

        // 返回
        //报警记录

        log.debug("根据设设备唯一码，查询当前设备是否开启 报警---------");

        log.debug("当前设备唯一码， alarmStatus = 0 不记录报警" );

        log.debug("当前设备唯一码， alarmStatus = 2 找设备关联的验证对象" );

        log.debug("当前设备唯一码， alarmStatus = 1 开启验证" );
        String payload_tt = null;
        List<ConfigAlarmDO> list = configAlarmService.list(new ConfigAlarmDO().setArarmStatus("1")); //启用的
        for (ConfigAlarmDO configAlarmDO : list) {
            if (!"1".equals(configAlarmDO.getAlarmType())) {
                continue;
            }
            // 余氯1  ph值2  浊度3  温度4
            DataTypeEnum dataType = DataTypeEnum.fromCode(configAlarmDO.getDataType());
            switch (dataType) {
                case YL:
                    payload_tt = createReqVO.getPayloadYl();
                    break;
                case PH:
                    payload_tt = createReqVO.getPayloadPh();
                    break;
                case WD:
                    payload_tt = createReqVO.getPayloadWd();
                    break;
                case ZD:
                    payload_tt = createReqVO.getPayloadZd();
                    break;
            }

            if (payload_tt == null) {
                continue;
            }
            if (MqttDeviceUtil.isOutOfRange(payload_tt, configAlarmDO.getGreaterValue(), configAlarmDO.getLessValue())) {
                String message = String.format("%s >[%s]> %s，实际值: %s",
                        configAlarmDO.getLessValue()+configAlarmDO.getUnit(), dataType.getDescription(), configAlarmDO.getGreaterValue()+configAlarmDO.getUnit(), payload_tt+configAlarmDO.getUnit());
                log.debug(" - ------------------ " +  message);
                String finalPayload_tt = payload_tt;
                TenantContextUtil.executeWithTenantContext(() -> {
                    DeviceAlermRecordDO recordDO = DeviceAlermRecordDO.builder()
                            .subscribeWaterId(createReqVO.getId()) //关联 ID
                            .alarmType(configAlarmDO.getAlarmType())
                            .dataType(configAlarmDO.getDataType())
                            .deviceKey("deviceKey -- ")
                            .isWeixin(configAlarmDO.getOpenWeixin())      //* 微信通知： 0 关闭不通知 1等待通知，2 已经通知
                            .isQms(configAlarmDO.getOpenSms())
                            .exceedValue(finalPayload_tt)
                            .isOnline("1")
                            .alarmInfo(message)
                            .mqttInfo(payload)
                            .build();
                    deviceAlermRecordMapper.insert(recordDO);

                });
            }
        }


        return CompletableFuture.completedFuture(createReqVO.getId());
    }

    @Override
    public void updateSubscribeWater(SubscribeWaterSaveReqVO updateReqVO) {
        // 校验存在
        validateSubscribeWaterExists(updateReqVO.getId());
        // 更新
        SubscribeWaterDO updateObj = BeanUtils.toBean(updateReqVO, SubscribeWaterDO.class);
        subscribeWaterMapper.updateById(updateObj);
    }

    @Override
    public void deleteSubscribeWater(Long id) {
        // 校验存在
        validateSubscribeWaterExists(id);
        // 删除
        subscribeWaterMapper.deleteById(id);
    }

    @Override
        public void deleteSubscribeWaterListByIds(List<Long> ids) {
        // 校验存在
        validateSubscribeWaterExists(ids);
        // 删除
        subscribeWaterMapper.deleteByIds(ids);
        }

    private void validateSubscribeWaterExists(List<Long> ids) {
        List<SubscribeWaterDO> list = subscribeWaterMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(SUBSCRIBE_WATER_NOT_EXISTS);
        }
    }

    private void validateSubscribeWaterExists(Long id) {
        if (subscribeWaterMapper.selectById(id) == null) {
            throw exception(SUBSCRIBE_WATER_NOT_EXISTS);
        }
    }

    @Override
    public SubscribeWaterDO getSubscribeWater(Long id) {
        return subscribeWaterMapper.selectById(id);
    }

    @Override
    public PageResult<SubscribeWaterDO> getSubscribeWaterPage(SubscribeWaterPageReqVO pageReqVO) {
        // 通过mqtt_config_id到配置表查询客户端id，用客户端id过滤数据
        if (pageReqVO.getMqttConfigId() != null) {
            MqttConfig2DO mqttConfig2DO = mqttConfig2Mapper.selectById(pageReqVO.getMqttConfigId());
            pageReqVO.setClientId(mqttConfig2DO.getSubClientId());
        }
        return subscribeWaterMapper.selectPage(pageReqVO);
    }

    @Override
    public Map<String, Object> getZtx(String deviceKey) {
        Map<String, Object> map = new HashMap<>();

        List<String> XList = new ArrayList<>();
        List<Double> yWdList = new ArrayList<>();
        List<Double> yZdList = new ArrayList<>();
        List<Double> yYlList = new ArrayList<>();
        List<Double> yPhList = new ArrayList<>();
        SubscribeWaterPageReqVO vo = new SubscribeWaterPageReqVO();
        vo.setDeviceKey(deviceKey);
        vo.setPageSize(6);
        vo.setPageNo(1);
        PageResult<SubscribeWaterDO> subscribeWaterDOPageResult = subscribeWaterMapper.selectPage(vo);
        List<SubscribeWaterDO> list = subscribeWaterDOPageResult.getList();
        // 常用模式：yyyy-MM-dd HH:mm:ss
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
        list.forEach(subscribeWaterDO -> {
            String formattedDateTime = subscribeWaterDO.getCreateTime().format(formatter);
            XList.add(formattedDateTime);
            Double wd = Double.parseDouble(subscribeWaterDO.getPayloadWd());
            Double wdRound = Math.round(wd * 100) / 100.0;
            yWdList.add(wdRound) ;

            Double zd = Double.parseDouble(subscribeWaterDO.getPayloadZd());
            Double zdRound = Math.round(zd * 100) / 100.0;
            yZdList.add(zdRound) ;

            Double yl = Double.parseDouble(subscribeWaterDO.getPayloadYl());
            Double ylRound = Math.round(yl * 100) / 100.0;
            yYlList.add(ylRound) ;

            Double ph = Double.parseDouble(subscribeWaterDO.getPayloadPh());
            Double phRound = Math.round(ph * 100) / 100.0;
            yPhList.add(phRound) ;
        });

        map.put("XList", XList);
        map.put("yWdList", yWdList.toArray(new Double[yWdList.size()]));
        map.put("yZdList", yZdList.toArray(new Double[yZdList.size()]));
        map.put("yYlList", yYlList.toArray(new Double[yYlList.size()]));
        map.put("yPhList", yPhList.toArray(new Double[yPhList.size()]));
        return map;
    }
}